/**
 * 
 */
package com.facebookfetcher.main;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Timer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.facebookdirectory.entity.FBAppInfo;
import com.facebookfetcher.Utlity.GlobalValue;

/**
 * @author piglet
 *
 */
public class FacebookFetcher {
	protected static final Log logger = LogFactory.getLog("FacebookFetcher");
	protected static final FacebookDataSource fbDataSource= new FBDataSourceImpl();
	//protected static final FacebookDataSource fbDataSource= new FBDataSourceDummy();
	private static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "FacebookFetcher" );
	private static final String[] FBAppIdTest = {"291549705119", "2462551974","8011067698",
											"182035348499485","177445378973723","291549705119"};
	Pattern pattern = Pattern.compile("\\d{9,18}");
	private MailBox mailBox = new MailBox();
	private static final FacebookFetcher fbFetcher = new FacebookFetcher();
	private static final String SPLITTER = ";";
	
	
	public static FacebookFetcher getInstance()
	{
		return fbFetcher;
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {			
		Timer FBTimer = new Timer("FBAppFetch task");             								
		FBTimer.schedule(new FBAppFetchTask(), 0, GlobalValue.getWorkInterval());
		BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
		try {						
			while(true)
			{
				System.out.println("type \"q\" to quit.");
				if(input.readLine().equals("q"))
					break;	
			}
		} catch (IOException e) {
			e.printStackTrace();			
		}
		finally
		{
			FBTimer.cancel();	
		}
						
		logger.info("Finish Application Actively");
	}

	public boolean working()
	{
		boolean ret = true; // false to finish timer;
		logger.info("Start Work");
		
		//DB update List
		updateDB();
		
		//Check Email		
		List<Request> emailRequestList = getEmailRequestList();
		logger.info("update from email:"+emailRequestList.size());		
		List<String> links = fbDataSource.getFetchLink(emailRequestList);								
		for(String link:links)
		{
			fbFetcher.fetchFBApp(link, true);
		}	
		
		logger.info("End Work with "+ ret);
		return ret;
	}
	
	private void updateDB() {
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		entityManager.getTransaction().begin();
		Query query = entityManager.createQuery("SELECT app FROM FBAppInfo app WHERE app.valid = true and app.category='Games' and app.lastUpdate < :bench order by app.lastUpdate asc", FBAppInfo.class);
		query.setParameter("bench", GlobalValue.getBenchmark());
		query.setMaxResults(5);
		List<FBAppInfo> infoList = query.getResultList();		
		if(infoList.isEmpty())
		{
			logger.info("no update from db");
		}		
		for(FBAppInfo appInfoRestore:infoList)
		{
			//update		
			FBAppInfo fbAppInfo = fbDataSource.getAppInfo(appInfoRestore.getMainURL());
			logger.info("update Facebook Application:"+fbAppInfo);
			
			if(fbAppInfo!=null)
			{
				appInfoRestore.assign(fbAppInfo);
				appInfoRestore.updateStatistic();
			}		
			else
			{
				appInfoRestore.setValid(false);
			}			
		}	
		entityManager.getTransaction().commit();
		entityManager.close();				
	}

	private List<Request> getEmailRequestList() {
		List<Request> appIdList = new ArrayList<Request>();
		for(String request:mailBox.getNewMessages())
		{			
			logger.info("mail:"+request);
			appIdList.addAll(parseSubject(request));			
		}		
		return appIdList;
	}

	private List<Request> parseSubject(String subject) {
		List<Request> result = new ArrayList<Request>();		
//		Matcher matcher = pattern.matcher(subject.toLowerCase());
		String[] strList = subject.split(SPLITTER);
		for(String str:strList)
		{
			if(str.matches("\\d+"))
			{
				//AppId
				result.add(new Request(str.trim(),Request.Type.AppId));
			}
			else
			{				
				//Profile Name							
				result.add(new Request(str.trim(),Request.Type.Name));								
			}
		}
//		// Check all occurance
//		while (matcher.find()) {
//			logger.debug("Start index: " + matcher.start());
//			logger.debug(" End index: " + matcher.end() + " ");
//			appId = matcher.group();			
//		}		
		return result;
	}

	/**
	 * @param appId
	 * @param immediate if true, ignore lastupdate timestamp
	 */
	public void fetchFBApp(String link, boolean immediate) {
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		entityManager.getTransaction().begin();
		Query query = entityManager.createQuery("SELECT app FROM FBAppInfo app WHERE  app.mainURL = :url", FBAppInfo.class);
		query.setParameter("url", link);
		FBAppInfo appInfoRestore = null;
		try
		{
			appInfoRestore = (FBAppInfo) query.getSingleResult();
		}
		catch (NoResultException e)
		{
			
		}
		if(appInfoRestore!=null)
		{
			//update
			if(appInfoRestore.isValid()&&(immediate||needUpdate(appInfoRestore)))
			{
				FBAppInfo fbAppInfo = fbDataSource.getAppInfo(link);
				logger.info("update Facebook Application:"+fbAppInfo);
				if(fbAppInfo!=null)
				{
					appInfoRestore.assign(fbAppInfo);
					appInfoRestore.updateStatistic();
				}			
			}						
		}
		else
		{
			//persist
			FBAppInfo fbAppInfo = fbDataSource.getAppInfo(link);
			logger.info("create Facebook Application:"+fbAppInfo);
			if(fbAppInfo!=null)
			{		
				fbAppInfo.updateStatistic();
				entityManager.persist(fbAppInfo);
			}
//			else
//			{
//				FBAppInfo temp = new FBAppInfo();
//				temp.setId(appId);
//				temp.setValid(false);
//				entityManager.persist(temp);
//			}
			
		}
		entityManager.getTransaction().commit();
		entityManager.close();		
		
	}
	
	private boolean needUpdate(FBAppInfo appInfoRestore) {		
		if(GlobalValue.getBenchmark().after(appInfoRestore.getLastUpdate()))
		{
			return true;
		}
		
		return false;
	}
	
	
}
